When you apply the Serializable attribute to a class, it affects only that class—it doesn't make any derived classes serializable, because the Inherited property of the AttributeUsage attribute applied on the Serializable attribute is set to false. For example, if you derive MyClass from MyBaseClass, MyClass isn't serializable:
[Serializable]
public class MyBaseClass
{}
public class MyClass : MyBaseClass
{}
At first glance this may appear awkward, but it does make design sense: MyBaseClass
has no way of knowing whether its subclasses will have non-serializable
members, so it would be wrong for them to automatically inherit the
serializable status. If you design a class hierarchy and you want to
support serialization of any type in the hierarchy, be sure to mark each
level with the Serializable attribute:
[Serializable]
public class MyBaseClass
{}
[Serializable]
public class MyClass : MyBaseClass
{}
[Serializable]
public class MyOtherClass : MyClass
{}
1. Custom Serialization and Base Classes
If any of the classes in the hierarchy implements ISerializable, there are a few design guidelines you have to follow to allow subclasses to provide their own custom serialization and to correctly manage the custom serialization of the base classes:
Only the topmost base class that uses custom serialization needs to derive from ISerializable.
When using implicit interface implementation, a base class must define its GetObjectData( ) method as virtual to allow subclasses to override it.
In a subclass implementation of GetObjectData( ), after serializing its own state, the subclass must call its base class's implementation of GetObjectData( ).
In its implementation of the deserializing constructor, the subclass must call its base class's deserializing constructor.
The deserializing constructor should be protected, to allow a subclass to call its base class's deserializing constructor.
Example 1
demonstrates how to implement these points; you can use it as a
template for combining custom serialization and class hierarchies.
Example 1. Combining custom serialization with a class hierarchy
[Serializable]
public class MyBaseClass : ISerializable
{
public MyBaseClass( )
{}
int m_BaseNumber;
public virtual void GetObjectData(SerializationInfo info,
StreamingContext context)
{
//Add MyBaseClass members
GenericSerializationInfo genericInfo = new GenericSerializationInfo(info);
genericInfo.AddValue("m_BaseNumber",m_BaseNumber);
}
protected MyBaseClass(SerializationInfo info,StreamingContext context)
{
//Read MyBaseClass members and initialize them
GenericSerializationInfo genericInfo = new GenericSerializationInfo(info);
m_BaseNumber = genericInfo.GetValue<int>("m_BaseNumber");
}
}
[Serializable]
public class MySubClass : MyBaseClass
{
public MySubClass( )
{}
int m_SubNumber;
public override void GetObjectData(SerializationInfo info,
StreamingContext context)
{
//Add MySubClass members
GenericSerializationInfo genericInfo = new GenericSerializationInfo(info);
genericInfo.AddValue("m_SubNumber",m_SubNumber);
base. GetObjectData(info,context);
}
protected MySubClass(SerializationInfo info,StreamingContext context):
base(info,context)
{
//Read MySubClass members and initialize them
GenericSerializationInfo genericInfo = new GenericSerializationInfo(info);
m_SubNumber = genericInfo.GetValue<int>("m_SubNumber");
}
}
|
If a base class provides custom serialization, all subclasses derived from it can use only custom serialization. |